package com.skyline.energy.jdbc.datasource;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.skyline.common.utils.Assert;
import com.skyline.energy.jdbc.impl.SqlThreadLocal;

public class ShardingDataSource extends AbstractDistributeDataSource {
	private static final Logger LOGGER = LoggerFactory.getLogger(ShardingDataSource.class);

	private List<NodeDataSource> normalNodes = Collections.emptyList();
	private List<NodeDataSource> insertNodes = Collections.emptyList();
	private RouteAlgorithm insertAlgorithm;
	private RouteAlgorithm normalAlgorithm;

	public void setInsertAlgorithm(RouteAlgorithm insertAlgorithm) {
		this.insertAlgorithm = insertAlgorithm;
	}

	public void setNormalAlgorithm(RouteAlgorithm normalAlgorithm) {
		this.normalAlgorithm = normalAlgorithm;
	}

	public void setDataSources(List<NodeDataSource> nodes) {
		normalNodes = new ArrayList<NodeDataSource>(nodes);

		// 按照startNumber的倒序排列，这样路由时直接判断是否大于当前记录即可取到需要的数据源
		sortNodes();

		addToInsertNodes(nodes);
	}

	private void addToInsertNodes(List<NodeDataSource> nodes) {
		for (NodeDataSource dataSource : nodes) {
			if (dataSource.isInsertable()) {
				insertNodes.add(dataSource);
			}
		}
	}

	private void sortNodes() {
		// 按照startNumber的倒序排列，这样路由时直接判断是否大于当前记录即可取到需要的数据源
		Collections.sort(normalNodes, new Comparator<NodeDataSource>() {
			@Override
			public int compare(NodeDataSource dataSource1, NodeDataSource dataSource2) {
				if (dataSource1.getStartNumber() < dataSource2.getStartNumber()) {
					return 1;
				} else if (dataSource1.getStartNumber() > dataSource2.getStartNumber()) {
					return -1;
				} else {
					LOGGER.error("系统配置了两个起始记录相同的数据源");
					return 0;
				}
			}
		});
	}

	@Override
	protected DataSource getDataSource() {
		SqlThreadLocal local = SqlThreadLocal.get();
		Assert.notNull(local, "系统BUG，请联系作者");

		if (local.isInsertType()) {
			return insertAlgorithm.route(local.getShardKey(), insertNodes);
		} else {
			return normalAlgorithm.route(local.getShardKey(), normalNodes);
		}
	}

}
